﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Dependencies;
using StructureMap;
using System.Web.Http.Dispatcher;
using System.Web.Http.Controllers;
using System.Net.Http;

namespace WebApp.Bootstrap.StructureMap
{
    public class ApiStructureMapDependencyScope : IDependencyScope
    {
        private IContainer _container;

        public ApiStructureMapDependencyScope(IContainer container)
        {
            if (container == null)
                throw new ArgumentNullException("container");

            this._container = container;
        }

        public object GetService(Type serviceType)
        {
            if (_container == null)
                throw new ObjectDisposedException("this", "This scope has already been disposed.");

            return _container.TryGetInstance(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            if (_container == null)
                throw new ObjectDisposedException("this", "This scope has already been disposed.");

            return _container.GetAllInstances(serviceType).Cast<object>();
        }

        public void Dispose()
        {
            _container.Dispose();
            _container = null;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <example>
    /// System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver =
    ///     new Bootstrap.StructureMap.ApiStructureMapResolver(ObjectFactory.Container);
    /// </example>
    public class ApiStructureMapResolver : ApiStructureMapDependencyScope, IDependencyResolver, IHttpControllerActivator
    {
        private readonly IContainer _container;

        public ApiStructureMapResolver(IContainer container)
            : base(container)
        {
            if (container == null)
                throw new ArgumentNullException("container");

            this._container = container;

            this._container.Inject(typeof(IHttpControllerActivator), this);
        }

        public IDependencyScope BeginScope()
        {
            /// GetNestedContainer is introduced after version 2.6.1,it will not track instances it creates
            /// a nested container tracks all transient instances (ie: non-singleton, non-thread-local instances) 
            /// and will dispose of them for you whenever you dispose the nested container. 

            return new ApiStructureMapDependencyScope(_container.GetNestedContainer());
        }

        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            //var controller = (IHttpController)_container.GetInstance(controllerType);

            var controller = (IHttpController)_container.GetNestedContainer().GetInstance(controllerType);

            /// http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/
            //request.RegisterForDispose(new Release(() =>
            //{
            //    IDisposable api = controller as IDisposable;
            //    if (api != null)
            //    {
            //        api.Dispose();
            //    }
            /* 
             * 经过测试，没必要在这进行dispose，框架会自动dispose 
             * 由HttpControllerHandler负责释放
             * 1，调用HttpRequestMessage的扩展方法RegisterForDispose
             * 2，调用TttpRequestMessage本身的Dispose方法对请求本身做释放工作
             * 3，调用返回的HttpReponseMessage对象，对响应做释放工作
             */
            //    /// Resolve == Release
            //}));

            return controller;
        }

        private class Release : IDisposable
        {
            private readonly Action release;

            public Release(Action release)
            {
                this.release = release;
            }

            public void Dispose()
            {
                this.release();
            }
        }
    }
}